﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Globalization;

class fw_update_mock
{
    static int Main(string[] args)
    {
        try
        {
            var argEnum = args.AsEnumerable().GetEnumerator();
            if (!argEnum.MoveNext())
                throw new Exception("Please use the command lines like the real thing...");
            return RunMockUpdate(int.Parse(argEnum.Current), argEnum);
        }
        catch (Exception e)
        {
            Console.WriteLine("ERROR: {0}", e.Message);
        }
        return -1;
    }
    static int RunMockUpdate(int which, IEnumerator<string> curArg)
    {
        bool ver = false;
        bool e = false;
        bool w = false;
        bool v = false;
        string vid = null;
        string pid = null;
        string file = null;
        while (curArg.MoveNext())
        {
            string arg = curArg.Current;
            switch (arg)
            {
                case "-ver":
                    ver = true;
                    break;
                case "-e":
                    e = true;
                    break;
                case "-w":
                    w = true;
                    break;
                case "-v":
                    v = true;
                    break;
                case "-vid":
                    ParseHex(ref vid, "vid", curArg);
                    break;
                case "-pid":
                    ParseHex(ref pid, "pid", curArg);
                    break;
                case "-ix":
                    if (!curArg.MoveNext())
                        throw new Exception("Missing file name argument for -ix");
                    if (file != null)
                        throw new Exception("More than 1 -ix file.hex not allowed");
                    file = curArg.Current;
                    if (!File.Exists(file))
                        throw new Exception("Unable to find file " + file);
                    break;
                default:
                    throw new Exception(string.Format("Unknown command line arg '{0}'", arg));
            }
        }

        if (vid.ToLowerInvariant() != "0x04d8" || pid.ToLowerInvariant() != "0xf6fc")
            throw new Exception(string.Format("Invalid vid or pid value specified. {0} {1} should be 0x04d8 0xf6fc.", vid, pid));

        if (ver)
            Console.WriteLine("fw_update Version: 0.2.0");
        // We're just asking for the version...
        if (file == null)
        {
            if (which != 1)
            {
                Console.WriteLine("U2IO BootLoader Version reading: DONE.");
                Console.WriteLine("BootLoader Version: 0.2.2");
                return 0;
            }
            else
            {
                Console.WriteLine("U2IO BootLoader Version reading: FAILED.");
                Console.WriteLine("Device is not found.");
                Console.WriteLine("Operation aborted.");
                return 2;
            }
        }

        // Okay, we're supposed to be 
        if (!e || !w || !v)
            throw new Exception("Missing -e, -w, or -v");
        if (which == 0)
        {
            ShowStatus(false);
            Console.WriteLine("U2IO flash verifying: DONE.");
            Console.WriteLine("RESET Device");
            Console.WriteLine("Operation successfully completed.");
            return 0;
        }
        else if (which == 2)
        {
            Console.WriteLine("U2IO flash erasing: FAILED.");
            Console.WriteLine("Device is not found.");
            Console.WriteLine("Operation aborted.");
            return 1;
        }
        else if (which == 3)
        {
            ShowStatus(true);
            Console.WriteLine("HID response ID doesn't correspond to command ID.");
            Console.WriteLine("Operation aborted.");
            return 3;
        }
        else
        {
            ShowStatus(true);
            Console.WriteLine("HID buffer read timeout.");
            Console.WriteLine("Operation aborted.");
            return 4;
        }
    }

    private static void ShowStatus(bool fail)
    {
        Console.WriteLine("U2IO flash erasing: DONE.");
        Console.Write("U2IO flash programming: ");
        var rand = new Random();
        var stop = fail ? rand.Next(100) : 100;
        int last = 0;
        for (int i = 1; i < stop; i += rand.Next(2) + 1)
        {
            Thread.Sleep(rand.Next(50));
            Backup(last);
            Console.Write("{0}%", i);
            last = i;
        }
        Backup(last);
        if (fail)
            Console.WriteLine("FAILED.");
        else
            Console.WriteLine("DONE.");
    }

    private static void Backup(int i)
    {
        if (i > 0)
        {
            if (i < 10)
                Console.Write("\b\b");
            else
                Console.Write("\b\b\b");
        }
    }

    private static void ParseHex(ref string id, string name, IEnumerator<string> enumer)
    {
        if (id != null)
            throw new Exception(string.Format("More than 1 -{0} argument not allowed", name));
        if (!enumer.MoveNext())
            throw new Exception(string.Format("Missing argument for -{0}", name));
        id = enumer.Current;
    }
}
